"""
WebSocket认证中间件 - 基于Token的真实用户认证
"""
import logging
from django.contrib.auth.models import AnonymousUser
from django.contrib.auth import get_user_model
from channels.middleware import BaseMiddleware
from channels.db import database_sync_to_async
from rest_framework.authtoken.models import Token
from urllib.parse import parse_qs

logger = logging.getLogger(__name__)
User = get_user_model()


@database_sync_to_async
def get_user_from_token(token_key):
    """根据token获取用户"""
    try:
        token = Token.objects.select_related('user').get(key=token_key)
        user = token.user
        if user.is_active:
            logger.info(f"🔍 Token认证成功，用户: {user.username}")
            return user
        else:
            logger.warning(f"⚠️ 用户已禁用: {user.username}")
            return AnonymousUser()
    except Token.DoesNotExist:
        logger.warning(f"❌ Token不存在: {token_key[:10]}...")
        return AnonymousUser()
    except Exception as e:
        logger.error(f"❌ Token认证失败: {e}")
        return AnonymousUser()


@database_sync_to_async
def get_user_from_access_token(access_token):
    """根据SSH访问令牌获取用户"""
    try:
        from django.core.cache import cache

        cache_key = f"ssh_access_token:{access_token}"
        token_data = cache.get(cache_key)

        if not token_data:
            logger.warning(f"❌ SSH访问令牌无效或已过期: {access_token[:10]}...")
            return AnonymousUser()

        # 从token数据中获取用户ID
        user_id = token_data.get('user_id')
        if not user_id:
            logger.warning(f"❌ SSH访问令牌缺少用户ID")
            return AnonymousUser()

        # 获取用户对象
        user = User.objects.get(id=user_id)
        if user.is_active:
            logger.info(f"🔍 SSH访问令牌认证成功，用户: {user.username}")
            return user
        else:
            logger.warning(f"⚠️ 用户已禁用: {user.username}")
            return AnonymousUser()

    except User.DoesNotExist:
        logger.warning(f"❌ 用户不存在: user_id={user_id}")
        return AnonymousUser()
    except Exception as e:
        logger.error(f"❌ SSH访问令牌认证失败: {e}")
        return AnonymousUser()


class TokenAuthMiddleware(BaseMiddleware):
    """
    WebSocket Token认证中间件 - 基于真实Token认证
    """

    def __init__(self, inner):
        super().__init__(inner)

    async def __call__(self, scope, receive, send):
        # 只处理WebSocket连接
        if scope["type"] != "websocket":
            return await super().__call__(scope, receive, send)

        # 获取WebSocket路径
        path = scope.get('path', '')

        # 从查询参数中获取token
        query_string = scope.get('query_string', b'').decode('utf-8')
        access_token = None
        auth_token = None

        if query_string:
            query_params = parse_qs(query_string)
            # 获取令牌
            token = query_params.get('token', [None])[0]

            # 根据路径判断令牌类型
            if '/docker/' in path:
                # Docker终端使用Django认证token
                auth_token = token
            else:
                # SSH终端使用访问令牌
                access_token = token

            # 获取用户认证令牌（备用）
            auth_token_param = query_params.get('auth', [None])[0]
            if auth_token_param:
                auth_token = auth_token_param

        # 如果没有auth token，尝试从headers获取
        if not auth_token:
            headers = dict(scope.get('headers', []))
            auth_header = headers.get(b'authorization')
            if auth_header:
                auth_str = auth_header.decode()
                if auth_str.startswith('Token '):
                    auth_token = auth_str[6:]  # 去掉 'Token ' 前缀

        # 根据令牌类型获取用户信息
        user = None

        # 如果有SSH访问令牌，从中获取用户信息
        if access_token:
            user = await get_user_from_access_token(access_token)

        # 如果没有从访问令牌获取到用户，尝试从认证令牌获取
        if not user and auth_token:
            user = await get_user_from_token(auth_token)

        # 如果都没有，使用匿名用户
        if not user:
            logger.warning(f"⚠️ WebSocket连接缺少有效的认证信息，路径: {path}")
            user = AnonymousUser()

        # 将用户信息添加到scope
        scope["user"] = user

        return await super().__call__(scope, receive, send)


def TokenAuthMiddlewareStack(inner):
    """
    WebSocket认证中间件栈
    """
    return TokenAuthMiddleware(inner)
